﻿namespace System.ComponentModel.Composition.SilverlightControlExtensions.Infrastructure
{
    using System.Collections.Generic;
    using System.ComponentModel.Composition.Hosting;
    using System.ComponentModel.Composition.Primitives;
    using System.Linq;
    using System.Windows;

    public delegate void ConpositionCompletedEventHandler();

    public static class Composition
    {
        public static readonly DependencyProperty CatalogProperty = DependencyProperty.RegisterAttached(
            "Catalog", typeof(ComposablePartCatalog), typeof(Application), new PropertyMetadata(null));

        public static readonly DependencyProperty ComposeProperty = DependencyProperty.RegisterAttached(
            "Compose", typeof(bool), typeof(UIElement), new PropertyMetadata(false));

        public static readonly DependencyProperty ExportProviderProperty =
            DependencyProperty.RegisterAttached(
                "ExportProvider", typeof(ExportProvider), typeof(UIElement), new PropertyMetadata(null));

        private static ExportProvider _applicationExportProvider;

        private static List<Action> _applicationCompositionActions;

        private static bool _xapsAllDownloaded;

        public static void ApplicationCompositionActionsAdd(this Application application, Action compositionAction)
        {
            if (_applicationCompositionActions == null)
            {
                _applicationCompositionActions = new List<Action>();
            }

            _applicationCompositionActions.Add(compositionAction);
        }

        public static List<Action> GetApplicationCompositionActions(this Application application)
        {
            return _applicationCompositionActions;
        }

        public static ExportProvider GetApplicationExportProvider(this Application application)
        {
            var exportProvider = _applicationExportProvider;
            return exportProvider;
        }

        public static bool GetApplicationXapsAllDownloaded(this Application application)
        {
            return _xapsAllDownloaded;
        }

        public static ComposablePartCatalog GetCatalog(DependencyObject obj)
        {
            return null;
        }

        public static bool GetCompose(DependencyObject obj)
        {
            return (bool)obj.GetValue(ComposeProperty);
        }

        public static ICompositionService GetCompositionService(UIElement element)
        {
            return (ICompositionService)GetExportProvider(element);
        }

        public static ExportProvider GetExportProvider(UIElement element)
        {
            var exportProvider = (ExportProvider)element.GetValue(ExportProviderProperty);
            if (exportProvider == null)
            {
                exportProvider = Application.Current.GetApplicationExportProvider();
            }

            return exportProvider;
        }

        public static void SetApplicationExportProvider(this Application application, ExportProvider provider)
        {
            _applicationExportProvider = provider;
        }

        public static bool SetApplicationImportedXapsCompleted(this Application application, bool xapsDownloaded)
        {
            return _xapsAllDownloaded;
        }

        public static void SetCatalog(Application application, Catalogs catalogs)
        {
            var innerCatalogs = catalogs.Items.Select(p => p.InnerCatalog);
            var deploymentCatalogs = innerCatalogs.Where(c => c.GetType() == typeof(DeploymentCatalog));
            var otherCatalogs = innerCatalogs.Where(c => c.GetType() != typeof(DeploymentCatalog));
            var deploymentCatalogsCount = deploymentCatalogs.Count();
            var aggregateCatalog = new AggregateCatalog(otherCatalogs);
            var downloadedDeploymentCatalogs = 0;
            foreach (DeploymentCatalog deploymentCatalog in deploymentCatalogs)
            {
                deploymentCatalog.DownloadCompleted += (s, args) =>
                    {
                        if (args.Error != null)
                        {
                            throw args.Error;
                        }

                        downloadedDeploymentCatalogs++;
                        if (downloadedDeploymentCatalogs == deploymentCatalogsCount)
                        {
                            application.SetApplicationImportedXapsCompleted(true);
                            var actions = application.GetApplicationCompositionActions();
                            actions.ForEach(x => x.Invoke());
                        }
                    };
                deploymentCatalog.DownloadAsync();
                aggregateCatalog.Catalogs.Add(deploymentCatalog);
            }

            var container = CompositionHost.Initialize(aggregateCatalog);
            application.SetApplicationExportProvider(container);
        }
    
        public static void SetCompose(UIElement element, bool shouldCompose)
        {
            element.SetValue(ComposeProperty, shouldCompose);
            if (shouldCompose)
            {
                var compositionService = GetCompositionService(element);
                if (compositionService != null)
                {
                    if (Application.Current.GetApplicationXapsAllDownloaded())
                    {
                        compositionService.SatisfyImportsOnce(element);
                    }
                    else
                    {
                        Application.Current.ApplicationCompositionActionsAdd(
                            () => { CompositionInitializer.SatisfyImports(element); });
                    }
                }
            }
        }

        public static void SetExportProvider(UIElement element, ExportProvider exportProvider)
        {
            element.SetValue(ExportProviderProperty, exportProvider);
        }
    }
}